"""
Adapters -- Layer 3
Adapters change the semantics of the underlying stream, providing an 
abstraction layer from the byte-level representation of layers 1 and 2. For 
example, layer 3 streams read and write python objects (strings, 
"""
import codecs
import struct
import cPickle as pickle


class Adapter(object):
    """the base, abstract adapter"""
    __slots__ = ["_substream"]
    
    def __init__(self, substream):
        self._substream = substream
    def __repr__(self):
        return "<%s(%r)>" % (self.__class__.__name__, self._substream)
    
    def close(self):
        self._substream.close()
    closed = property(lambda self: self._substream.closed)


class TextAdapter(Adapter):
    """an adapter for reading and writing (unicode) text, in various encodings.
    TextAdapter streams are iterable by lines"""
    __slots__ = ["_encoding", "_encoder", "_decoder"]
    
    class trivial_codec(object):
        def decode(self, data):
            return data
        def encode(self, data):
            return data
        def reset(self):
            pass
    _trivial_codec = trivial_codec()
    
    def __init__(self, substream, encoding = None):
        Adapter.__init__(self, substream)
        self._encoding = encoding
        if encoding is None:
            self._encoder = self._trivial_codec
            self._decoder = self._trivial_codec
        else:
            codec = codecs.lookup(encoding)
            self._encoder = codec.incrementalencoder()
            self._decoder = codec.incrementaldecoder()
    
    def __iter__(self):
        try:
            while True:
                yield self.readline()
        except EOFError:
            pass
    
    def read(self, count = -1):
        if count == 0:
            return ""
        if count < 0:
            return self.readall()
        return self._read(count)
    
    def _read(self, count):
        data = []
        try:
            while count:
                char = self._decoder.decode(self._substream.read(1))
                if char:
                    count -= 1
                    data.append(char)
        except EOFError:
            if not data: raise
        return "".join(data)
    
    def readline(self):
        pass
    
    def readall(self):
        return self._decoder.decode(self._substream.readall())
    
    def write(self, text):
        self._substream.write(self._encoder.encode(text))


class UnitAdapter(Adapter):
    """an abstract base adapter that works with 'units', i.e., read() takes no
    parameters and returns a unit (or EOFError). UnitAdapters are iterable by
    unit, and support readall()"""
    __slots__ = []
    
    def __iter__(self):
        try:
            while True:
                yield self.read()
        except EOFError:
            pass
    
    def readall(self):
        return list(self)


class StructAdapter(UnitAdapter):
    """reads and writes structures to the underlying stream. 'structures' are 
    arbitrary, fixed-sized data structures, defined by a format string of the
    struct module"""
    __slots__ = ["_format", "_size"]
    
    def __init__(self, substream, format):
        UnitAdapter.__init__(self, substream)
        self._format = format
        self._size = struct.calcsize(format)
    
    def read(self):
        return struct.unpack(self._format, self._substream.read(self._size))
    
    def write(self, *args):
        return self._substream.write(struct.pack(self._format, *args))


class FramingAdapter(UnitAdapter):
    """reads and writes frames to the stream. a frame is arbitrary data 
    prefixed by its length (called the frame header). the header can be one
    of several formats, supported by the struct module"""
    __slots__ = ["_header_format", "_header_size"]
    HEADER_FORMATS = ["B", "H", "L", "Q"]
    
    def __init__(self, substream, header_format = "L", little_endian = False):
        UnitAdapter.__init__(self, substream)
        if header_format not in self.HEADER_FORMATS:
            raise ValueError("`header_format` must be one of %r" % (self.HEADER_FORMATS,))
        if little_endian:
            header_format = "<" + header_format
        else:
            header_format = ">" + header_format
        self._header_format = header_format
        self._header_size = struct.calcsize(header_format)
    
    def read(self):
        header = self._substream.read(self._header_size)
        length, = struct.unpack(self._header_format, header)
        return self._substream.read(length)
    
    def write(self, data):
        header = struct.pack(self._header_format, len(data))
        self.substream.write(header)
        self.substream.write(data)


class ObjectAdapter(UnitAdapter):
    """reads (deserializes) and writes (serializes) arbitrary objects to the 
    stream, using pickle. ObjectAdapter expects to be stacked upon a 
    FramingAdpater"""
    __slots__ = ["_protocol"]
    
    def __init__(self, substream, pickle_protocol = pickle.HIGHEST_PROTOCOL):
        UnitAdapter.__init__(self, substream)
        self._protocol = pickle_protocol
    
    def read(self):
        return pickle.loads(self._substream.read())
    
    def writes(self, obj):
        self._substream.write(pickle.dumps(obj, protocol = self._protocol))






































